package com.dajia.hefei.nbiot.bean;

import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.List;

@Data
public class RuleDTO {
    private String ruleId;// 规则实例的ID，仅在规则更新时有效，创建规则时不填写。
    private String appKey;
    @Required
    private String name;// 规则名称
    private String description;// 规则描述
    @Required
    private String author;// 创建此规则的用户的ID
    private List<Object> conditions;// 条件列表，与groupExpress二选一必填，具体参见，ConditionDeviceData,ConditionDeviceGroupData,ConditionDeviceTypeData,ConditionDailyTimer,ConditionCycleTimer,ConditionNoDetected
    private OPERATOR logic;// 多条件之间的逻辑关系，支持and和or，默认为and
    private TimeRange timeRange;// 条件场景的时间段
    // 定时场景必选
    private List<Object> actions;// 满足规则所执行的动作，具体参加ActionDeviceCMD,ActionSMS,ActionEmail,ActionDelay,ActionRule,ActionDeviceAlarm,ActionEICMD
    private String matchNow;// 表示是否立即触发，即是否立即进行规则条件判断，条件符合的话执行动作。yes：立即触发；no：不触发
    private String status;// 规则的状态，默认为active状态。active：激活，inactive：未激活
    private GroupExpress groupExpress;// 复杂多条件表达式，具体参见GroupExpress结构体，与conditions二选一必填。
    private String timezoneID;// 时区ID。若为空，使用UTC时间；若不为空，使用本地时间。
    private List<Object> triggerSources;// 触发源列表，只与GroupExpress联用构造复杂多条件规则，目前有DEVICE类型和TIMER类型，具体参加TriggerSourceDevice和TriggerSourceTimer
    private String executor;// 规则执行主体，当action和condition里面的设备在同一个网关下面时，取值网管ID（代表网关执行）；否则取定值“cloud”（代表云端执行）。
    private Object transData;// 平台不需要识别的数据，只做保存
    private Boolean refreshId;// 穿件规则时是否检查ruleId不能为空标识，默认为true
    private Boolean checkNullAction;// 创建规则时是否检查Action不能为空标识，默认为true
    private String priority;// 规则优先级，保留字段。
    private List<TagDTO2> tags;// 标签列表
    private List<RulePreProcessorDTO> rulePreProcessors;// 规则的预处理器，不符合预处理条件的规则不执行


    @Data
    public static class TimeRange {
        @Required
        private String startTime;// 开始时间，格式为“HH:mm”
        @Required
        private String endTime;// 结束时间，格式为“HH:mm”，开始时间与结束时间一致，则认为是全天
        private String daysOfWeek;// 星期列表，以逗号分隔。1代表周日，2代表周一，以此类推，week周列表需要与开始时间保持一致，默认每天
    }

    @Data
    public static class GroupExpress {
        private OPERATOR operator;// 操作符and/or，默认为and
        @Required
        private List<GroupElement> groupElements;// 最外层操作符对应的元素
    }


    @Data
    private static class GroupElement {
        private OPERATOR operator;// 操作符and/or，默认为and
        @Required
        private List<Object> elements;// 内层表达式运算的元素，一个element表示一个condition，自定义结构conditions
    }

    @Data
    public static class RulePreProcessorDTO {
        @Required
        private String processor = "rulePreProcessorForDeviceTag";// 规则预处理类型，取值为：rulePreProcessorForDeviceTag
        @Required
        private Object param;// 根据预处理类型有对应的结构
    }

    @Data
    public static class RulePreProcessorForDeviceTag {
        private TagDTO3 tag;// 标签结构
        private List<String> nullTags;// 标签列表
    }

    @Data
    public static class TagDTO3 {
        @Required
        private String tagName;// 标签名
        @Required
        private String tagValue;// 标签值
        @Required
        private MATCHTYPE matchType;// tagValue的匹配方式，取值为Any|Right
    }

    @Data
    @EqualsAndHashCode(callSuper = true)
    public static class ConditionDeviceData extends ConditionBase {
        @Required
        private String type = "DEVICE_DATA";// 条件触发condition类型，取值为“DEVICE_DATA”
        @Required
        private DeviceInfo deviceInfo;// 设备数据的定位信息，根据定位信息读取的数据作为比较表达式的左值
    }

    @Data
    private static class DeviceInfo {
        @Required
        private String deviceId;// 设备ID
        @Required
        private String path;// 以“/”分割的信息路径，按照当前的数据模型，路径为ServiceId/DataProperty，例如门磁状态为：“DoorWindow/status”
    }

    @Data
    private static class Strategy {
        private STRATEGY_TRIGGER trigger;// 触发模式，默认为pulse。pulse：上报的数据满足条件则触发，不判断上一次的数据。reverse：上一次数据不满足条件，本次数据满足条件则触发。默认为pulse
        private Integer eValidTime;// 事件时效性，单位为秒，表示收到的传感器数据多久有效，以eventTime为基准。（取值>=-1）
    }

    @Data
    public static class ConditionBase {
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号。
        @Required
        private Object operator;// 数据比较的操作符（目前支持的操作符由：>,<,>=,<=,=,between,geo.circle.in,geo.circle.out）
        private String value;// 比较表达式的右值（与between操作符联用时，右值表示最小值和最大值用逗号隔开如“20，30”表示大于等于20小于30，应用场景：温度在20到30之前触发规则）
        private Object transInfo;// 不需要平台理解的信息
        private Integer duration;// 规则执行延时时间，单位为分钟，默认为0不延时。
        @Required
        private Strategy strategy;// 配置条件处理策略
    }

    @Data
    @EqualsAndHashCode(callSuper = true)
    public static class ConditionDeviceGroupData extends ConditionBase {
        @Required
        private String type = "DEVICE_DATA_GROUP";// 条件触发condition类型，取值为“DEVICE_DATA_GROUP”
        @Required
        private DeviceGroupInfo deviceGroupInfo;// 组设备数据的定位信息，根据地恭维信息读取的数据作为比较表达式的左值
    }

    @Data
    public static class DeviceGroupInfo {
        @Required
        private String groupId;// 设备组ID
        @Required
        private String path;// 以“/”分割的信息路径，按照当前的数据模型，路径为ServiceId/DataProperty，例如门磁状态为：“DoorWindow/status”，属性支持多个，比如OBD需要两个属性：经度和纬度，多个属性中间以逗号分割
    }

    @Data
    public static class ConditionDeviceTypeData {
        @Required
        private String type = "DEVICE_DATA_TYPE";// 条件触发condition类型，取值为“DEVICE_DATA_TYPE”
        private DeviceTypeInfo deviceTypeInfo;// 组设备数据的定位信息，根据定位信息读取的数据作为比较表达式的左值
    }

    @Data
    @Required
    public static class DeviceTypeInfo {
        private String manufactureId;// 厂商ID
        private String model;// 设备型号
        private String deviceType;// 设备类型
        private String protocolType;// 协议类型
        private String path;// 以“/”分割的信息路径，按照当前的数据模型，路径为ServiceId/DataProperty，例如门磁状态为：“DoorWindow/status”，属性支持多个，比如OBD需要两个属性：经度和纬度，多个属性中间以逗号分割

    }

    @Data
    public static class ConditionDailyTimer {
        @Required
        private String type = "DAILY_TIMER";// 定点触发condition类型，取值为“DAILY_TIMER”
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号
        @Required
        private String time;// 指定执行时间点，格式为“HH:MM”
        private String daysOfWeek;// 星期列表，以逗号分隔
    }

    @Data
    public static class ConditionCycleTimer {
        @Required
        private String type = "CYCLE_TIMER";// 周期性触发condition类型，取值为“CYCLE_TIMER”
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号
        @Required
        private TimeRange timeRange;// 限定的时间范围
        @Required
        private Integer interval;// 周期，单位为分钟
    }

    @Data
    public static class ConditionNoDetected {
        @Required
        private String type = "NO_DETECTED";// 不检测类型，说明这个条件在平台不进行检测，只存储条件的部分信息，用于终端手机app直接触发，比较检测到回家后直接触发action。取值为“NO_DETECTED”
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号
        private String description;// 条件描述
    }

    @Data
    public static class ActionDeviceCMD {
        @Required
        private String type = "DEVICE_CMD";// 设备命令action类型，取值为“DEVICE_CMD”
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号
        private String appKey;// 用于实例的key值
        private String deviceId;// 设备ID，对于不同的condition类型，该字段有不同约束：DEVICE_DATA/DEVICE_DATA_GROUP/DEVICE_DATA_TYPE，允许为空，命令下发给上报数据的设备，如果希望命令下发给其他设备，请务必携带：DAILY_TIMER/CYCLE_TIMER，不允许为空。
        @Required
        private CMD cmd;// 命令内容
        private String cmdVersion;// 下发命令的版本
        private Object cmdMetaData;// 下发命令的参数
        private Object transInfo;// 不需要平台理解的信息
        private List<DeviceCommandActionPreProcessor> deviceCommandActionPreProcessors;// 设备命令下发预处理器列表，符合预处理器条件的才允许给设备下发命令
    }

    @Data
    public static class CMD {
        @Required
        public String messageType;// 命令名字
        private Object messageBody;// 下发命令的消息内容
        @Required
        private String serviceId;// 设备服务的ID
        private String requestId;// 命令请求ID
        private String callbackUrl;// 命令状态变化通知地址，当命令状态变化时（执行失败，执行成功，超时，发送，已送达）会通知第三方应用。
        @Deprecated
        private Integer expireTime;// 已废弃参数，未使用
    }

    @Data
    public static class DeviceCommandActionPreProcessor {
        @Required
        private String processor = "deviceCommandActionPreProcessorForDeviceTag";// 折命令下发预处理类型，取值为“deviceCommandActionPreProcessorForDeviceTag”
        @Required
        private Object param;// 根据预处理类型有对应的结构

        @Data
        public static class DeviceCommandActionPreProcessorForDeviceTag {
            private TagDTO3 tag;// 标签结构
            private List<String> nullTags;// 标签列表
        }
    }

    @Data
    public static class ActionSMS {
        @Required
        private String type = "SMS";// 发送短信action类型，取值为“SMS”
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号
        @Required
        private String msisdn;// 短信通知地址
        private String content;// 短信的内容（短信content为空时，短信邮件由北向应用发送）
        private String subject;// 短信的主题
        private String title;// 短信的别名
        private String accountId;// 账户ID
    }

    @Data
    public static class ActionEmail {
        @Required
        private String type = "EMAIL";// 发送邮件action类型，取值为“EMAIL”
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号
        @Required
        private String email;// 邮箱地址
        private String content;// 邮件的内容（邮件content或者subject为空时，短信邮件由北向应用发送）
        private String subject;// 邮件的主题
        private String title;// 邮件的别名
        private String accountId;// 账户ID
    }

    @Data
    public static class ActionDelay {
        @Required
        private String type = "DELAY";// 延时命令actioin类型，取值为“DELAY”
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号
        @Required
        private Long time;// 延迟时间，单位时间秒
        private Object transInfo;// 透传数据，平台不需识别，只做保存
    }


    @Data
    public static class ActionRule {
        @Required
        private String type = "RULE";// 触发规则执行action类型，取值为“RULE”，用于可以执行终端的手工场景
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号
        @Required
        private String roleId;// 动作执行规则的规则ID
        @Required
        private RULE_CMD cmd;// 对规则执行的动作。EXECUTE：执行动作；ACTIVE：激活规则；DEACTIVE：去激活规则
    }

    @Data
    public static class ActionDeviceAlarm {
        @Required
        private String type = "DEVICE_ALARM";// 设备告警action类型，取值为“DEVICE_ALARM”
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号
        @Required
        private String name;// 告警名
        @Required
        private DEVICE_ALERM_STATUS status;// 告警状态fault/recovery
        @Required
        private DEVICE_ALERM_SEVERITY severity;// 告警级别 warning/minor/major/critical
        private String description;// 告警描述
    }

    @Data
    public static class ActionEICMD {
        @Required
        private String type = "EI_CMD";// 设备EIG命令action类型，取值为“EI_CMD”
        private String id;// 对condition的编号，在一条规则范围内唯一，不指定时由系统自动编号
        @Required
        private ACTION_EI_CMD_SUBSYSTEM subSystem;// 要发送的子系统名称，取值为：IVS/SNS/ICP其中之一
        private String deviceId;// 触发源设备ID
        @Required
        private String messageType;// 消息类型，需要与EIG通知对端子系统URL对齐。
        @Required
        private Object messageBody;// 需要推送的消息体。
    }

    @Data
    @Required
    public static class TriggerSourceDevice {
        private String type;// 设备触发源类型，取值为“DEVICE”
        private String deviceId;// 设备ID
        private String serviceId;// 服务ID
    }

    @Data
    public static class TriggerSourceTimer {
        @Required
        private String type = "TIMER";// 设备触发源类型，取值为“TIMER”
    }

    public enum STRATEGY_TRIGGER {
        pulse, reverse;
    }

    public enum ACTION_EI_CMD_SUBSYSTEM {
        IVS, SNS, ICP;
    }

    public enum DEVICE_ALERM_SEVERITY {
        warning, minor, major, critical;
    }

    public enum DEVICE_ALERM_STATUS {
        fault, recovery;
    }

    public enum RULE_CMD {
        EXECUTE/*执行动作*/,
        ACTIVE/*激活规则*/,
        DEACTIVE/*取消激活*/;
    }

    public enum OPERATOR {
        and, or;
    }

    public enum MATCHTYPE {
        Any, Right;
    }
}
